﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace BitcoinLibrary
{
    public class GetBlocksMessage : Message
    {
        private const long serialVersionUID = 3479412877853645644L;
        private readonly List<byte[]> locator;
        private readonly byte[] stopHash;

        public GetBlocksMessage(NetworkParameters param, List<byte[]> locator, byte[] stopHash)
            : base(param)
        {
            this.locator = locator;
            this.stopHash = stopHash;
        }

        public override void parse()
        {
        }

        public String toString()
        {
            StringBuilder b = new StringBuilder();
            b.Append("getblocks: ");
            foreach (byte[] hash in locator)
            {
                b.Append(Utils.bytesToHexString(hash));
                b.Append(" ");
            }
            return b.ToString();
        }

        public byte[] bitcoinSerialize()
        {
            try
            {
                MemoryStream buf = new MemoryStream();
                // Version, for some reason.
                Utils.uint32ToByteStreamLE(NetworkParameters.PROTOCOL_VERSION, buf);
                // Then a vector of block hashes. This is actually a "block locator", a set of block
                // identifiers that spans the entire chain with exponentially increasing gaps between
                // them, until we end up at the genesis block. See CBlockLocator::Set()
                var data = new VarInt(locator.Count).encode();
                buf.Write(data, 0, data.Length);
                foreach (byte[] hash in locator)
                {
                    // Have to reverse as wire format is little endian.
                    buf.Write(Utils.reverseBytes(hash), 0, hash.Length);
                }
                // Next, a block ID to stop at.
                buf.Write(stopHash, 0, stopHash.Length);
                return buf.ToArray();
            }
            catch (Exception e)
            {
                throw e; // Cannot happen.
            }
        }
    }
}
